{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true,
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "# Классификация рукописных цифр базы MNIST"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "outputs": [],
   "source": [
    "from collections import namedtuple\n",
    "\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "import PIL\n",
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.optim as optim\n",
    "import torchvision.datasets as dset\n",
    "from torch.utils.data.sampler import SubsetRandomSampler\n",
    "\n",
    "from torchvision import transforms\n",
    "\n",
    "from support import train_model, compute_loss_accuracy, Flattener"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU\n"
     ]
    }
   ],
   "source": [
    "if torch.cuda.is_available():\n",
    "    device = torch.device('cuda:0')\n",
    "    print(\"CUDA\")\n",
    "else:\n",
    "    device = torch.device('cpu')\n",
    "    print(\"CPU\")"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "Загружаем тренировочные данные"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Downloading http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz\n",
      "Downloading http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz to ./data/MNIST\\raw\\train-images-idx3-ubyte.gz\n"
     ]
    },
    {
     "data": {
      "text/plain": "  0%|          | 0/9912422 [00:00<?, ?it/s]",
      "application/vnd.jupyter.widget-view+json": {
       "version_major": 2,
       "version_minor": 0,
       "model_id": "236333ecce914897a485a1eab4df2bea"
      }
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Extracting ./data/MNIST\\raw\\train-images-idx3-ubyte.gz to ./data/MNIST\\raw\n",
      "\n",
      "Downloading http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz\n",
      "Downloading http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz to ./data/MNIST\\raw\\train-labels-idx1-ubyte.gz\n"
     ]
    },
    {
     "data": {
      "text/plain": "  0%|          | 0/28881 [00:00<?, ?it/s]",
      "application/vnd.jupyter.widget-view+json": {
       "version_major": 2,
       "version_minor": 0,
       "model_id": "233af55f80c245e795ee9c5c7da7f6d4"
      }
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Extracting ./data/MNIST\\raw\\train-labels-idx1-ubyte.gz to ./data/MNIST\\raw\n",
      "\n",
      "Downloading http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz\n",
      "Downloading http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz to ./data/MNIST\\raw\\t10k-images-idx3-ubyte.gz\n"
     ]
    },
    {
     "data": {
      "text/plain": "  0%|          | 0/1648877 [00:00<?, ?it/s]",
      "application/vnd.jupyter.widget-view+json": {
       "version_major": 2,
       "version_minor": 0,
       "model_id": "717d424c6371463e966b92ad4b071f7b"
      }
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Extracting ./data/MNIST\\raw\\t10k-images-idx3-ubyte.gz to ./data/MNIST\\raw\n",
      "\n",
      "Downloading http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz\n",
      "Downloading http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz to ./data/MNIST\\raw\\t10k-labels-idx1-ubyte.gz\n"
     ]
    },
    {
     "data": {
      "text/plain": "  0%|          | 0/4542 [00:00<?, ?it/s]",
      "application/vnd.jupyter.widget-view+json": {
       "version_major": 2,
       "version_minor": 0,
       "model_id": "107b62fe37bb45ae937e15f4124e1f37"
      }
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Extracting ./data/MNIST\\raw\\t10k-labels-idx1-ubyte.gz to ./data/MNIST\\raw\n",
      "\n"
     ]
    }
   ],
   "source": [
    "train_data = dset.MNIST('./data/', train=True, download=True,\n",
    "                    transform=transforms.Compose([\n",
    "                           transforms.ToTensor(),\n",
    "                           transforms.Normalize(mean=[0.43],\n",
    "                                               std=[0.20])\n",
    "                       ]))"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "Отобразим данные"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "outputs": [
    {
     "data": {
      "text/plain": "<Figure size 576x576 with 9 Axes>",
      "image/png": "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\n"
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "figure = plt.figure(figsize=(8, 8))\n",
    "cols, rows = 3, 3\n",
    "for i in range(1, cols * rows + 1):\n",
    "    sample_idx = torch.randint(len(train_data), size=(1,)).item()\n",
    "    img, label = train_data[sample_idx]\n",
    "    figure.add_subplot(rows, cols, i)\n",
    "    plt.title(str(label))\n",
    "    plt.axis(\"off\")\n",
    "    plt.imshow(img.squeeze(), cmap=\"gray\")\n",
    "plt.show()"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "Разделим тренировочные данные на тренировочные и валидационные"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "outputs": [],
   "source": [
    "data_size = train_data.data.shape[0]\n",
    "validation_proc = 0.2\n",
    "split = int(np.floor(validation_proc * data_size))\n",
    "indices = list(range(data_size))\n",
    "np.random.shuffle(indices)\n",
    "\n",
    "train_indices, val_indices = indices[split:], indices[:split]\n",
    "\n",
    "train_sampler = SubsetRandomSampler(train_indices)\n",
    "val_sampler = SubsetRandomSampler(val_indices)\n",
    "\n",
    "batch_size = 64\n",
    "\n",
    "train_loader = torch.utils.data.DataLoader(train_data, batch_size=batch_size,\n",
    "                                           sampler=train_sampler)\n",
    "valid_loader = torch.utils.data.DataLoader(train_data, batch_size=batch_size,\n",
    "                                         sampler=val_sampler)"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "### Создаем и тренируем модель\n",
    "Цели модели - достичь точности на тренировочных данных более 98% с менее чем 10.000 параметрами"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch #0 - train loss: 0.146808, accuracy: 0.954750 | val loss: 0.092629, accuracy: 0.971500\n",
      "Epoch #1 - train loss: 0.049103, accuracy: 0.985125 | val loss: 0.061797, accuracy: 0.980667\n",
      "Epoch #2 - train loss: 0.034140, accuracy: 0.988542 | val loss: 0.059324, accuracy: 0.982083\n",
      "Epoch #3 - train loss: 0.025178, accuracy: 0.992146 | val loss: 0.051237, accuracy: 0.984583\n",
      "Epoch #4 - train loss: 0.020239, accuracy: 0.993833 | val loss: 0.046568, accuracy: 0.985333\n",
      "Epoch #5 - train loss: 0.015522, accuracy: 0.995750 | val loss: 0.047723, accuracy: 0.984833\n",
      "Epoch #6 - train loss: 0.013201, accuracy: 0.996625 | val loss: 0.046882, accuracy: 0.985917\n",
      "Epoch #7 - train loss: 0.011558, accuracy: 0.997354 | val loss: 0.046846, accuracy: 0.984917\n",
      "Epoch #8 - train loss: 0.010664, accuracy: 0.997667 | val loss: 0.046822, accuracy: 0.986417\n",
      "Epoch #9 - train loss: 0.010169, accuracy: 0.997687 | val loss: 0.046137, accuracy: 0.985917\n",
      "Epoch #10 - train loss: 0.009778, accuracy: 0.998000 | val loss: 0.047074, accuracy: 0.985833\n",
      "Epoch #11 - train loss: 0.009740, accuracy: 0.998021 | val loss: 0.046782, accuracy: 0.985833\n",
      "Epoch #12 - train loss: 0.009510, accuracy: 0.998062 | val loss: 0.046697, accuracy: 0.985833\n",
      "Epoch #13 - train loss: 0.009446, accuracy: 0.998062 | val loss: 0.046717, accuracy: 0.986083\n",
      "Epoch #14 - train loss: 0.009479, accuracy: 0.998125 | val loss: 0.046845, accuracy: 0.986000\n",
      "Wall time: 4min 44s\n"
     ]
    }
   ],
   "source": [
    "# 6010 Параметров\n",
    "\n",
    "model = nn.Sequential(\n",
    "        # In 28x28@1, out 28x28@8 - 80 параметра\n",
    "        nn.Conv2d(1, 8, 3, padding=2),\n",
    "        nn.BatchNorm2d(num_features=8),\n",
    "        nn.ReLU(inplace=True),\n",
    "\n",
    "        # In 28x28@8, out 14x14@8\n",
    "        nn.MaxPool2d(kernel_size=2),\n",
    "\n",
    "        # In 14x14@8, out 12x12@16 - 160 параметра\n",
    "        nn.Conv2d(in_channels=8, out_channels=16, kernel_size=3),\n",
    "        nn.BatchNorm2d(num_features=16),\n",
    "        nn.ReLU(inplace=True),\n",
    "\n",
    "        # In 12x12@16, out 6x6@16\n",
    "        nn.MaxPool2d(kernel_size=2),\n",
    "\n",
    "\n",
    "        Flattener(),\n",
    "\n",
    "        # O7 In 6*6*16, out 10 - 5770 параметров\n",
    "        nn.Linear(6*6*16, 10),\n",
    "      )\n",
    "\n",
    "model.type(torch.FloatTensor)\n",
    "model.to(device)\n",
    "\n",
    "# Подобранные гиперпараметры для обучения сети\n",
    "learning_rates = 10**-2\n",
    "weight_decay = 10**-4\n",
    "step_size = 1\n",
    "gamma = 0.6\n",
    "num_epochs = 15\n",
    "\n",
    "loss = nn.CrossEntropyLoss().type(torch.FloatTensor)\n",
    "optimizer = optim.Adam(model.parameters(), lr=learning_rates, weight_decay=weight_decay)\n",
    "scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=step_size, gamma=gamma)\n",
    "\n",
    "%time train_loss_history, train_acc_history, val_loss_history, val_acc_history = train_model(model, train_loader, valid_loader, loss, optimizer, num_epochs, device, scheduler=scheduler, scheduler_loss=False)"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "Нарисуем график ошибок и точности во время тренировки"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "outputs": [
    {
     "data": {
      "text/plain": "<Figure size 432x288 with 1 Axes>",
      "image/png": "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\n"
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.plot(range(1, len(train_loss_history) + 1), train_loss_history, label=\"train loss\")\n",
    "plt.plot(range(1, len(val_loss_history) + 1), val_loss_history, label=\"validate loss\")\n",
    "plt.show()"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "outputs": [
    {
     "data": {
      "text/plain": "<Figure size 432x288 with 1 Axes>",
      "image/png": "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\n"
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.plot(range(1, len(train_acc_history) + 1), train_acc_history)\n",
    "plt.plot(range(1, len(val_acc_history) + 1), val_acc_history)\n",
    "plt.show()"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "Сохраняем модель для последующих тестов"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "outputs": [],
   "source": [
    "torch.save(model, \"./model_v3.pt\")"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}